/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package OPC;

import java.util.ArrayList;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafish.clients.opc.JEasyOpc;
import javafish.clients.opc.browser.JOpcBrowser;
import javafish.clients.opc.component.OpcGroup;
import javafish.clients.opc.component.OpcItem;
import javafish.clients.opc.exception.*;
import javafish.clients.opc.variant.Variant;

/**
 *
 * @author Danilo
 */
public class ConexaoOPC /*
 * implements Comparable<OPCUtil>
 */ {

    /**
     * Nome do cadastro de um servidor OPC
     */
    private int id;
    private String host;
    private String serverName;
    private boolean conectado;
    private boolean jbrowserConectado;
    private JEasyOpc jopc;
    private OpcGroup grupoPadrao;
    private SortedMap<String, OpcItem> variaveis;
    private static ConexaoOPC currentInstance;
    private JOpcBrowser jbrowser;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    static {
        // Inicializa a biblioteca JEasyOPC
        JEasyOpc.coInitialize();
    }

    /**
     * Finaliza a biblioteca JEasyOPC. Deve ser chamado no fim da execução do
     * programa.
     */
    public static void finalizar() {
        JEasyOpc.coUninitialize();
    }

    private ConexaoOPC(String host, String serverName, int id) {
        this.id = id;
        this.host = host;
        this.serverName = serverName;
        this.conectado = false;
        jbrowserConectado = false;
        this.jbrowser = new JOpcBrowser(host, serverName, "JOPCBrowser" + Math.random());
        this.jopc = new JEasyOpc(host, serverName, "JOPC" + Math.random());

        grupoPadrao = new OpcGroup("grupo", true, 100, 0.0f);//refresh de 100ms.
        variaveis = new TreeMap<String, OpcItem>();
    }

    /**
     * Conecta ao servidor OPC e executa o cliente.
     *
     * @param jopc
     */
    public void conectar() throws OPCException, UnableAddGroupException, ConnectivityException, UnableAddItemException {
            if (jopc.getGroupsAsArray().length > 0) {
                jopc.removeGroup(grupoPadrao);
            }

            jopc.addGroup(grupoPadrao);
            jopc.connect();
            jopc.registerGroups();

            conectado = true;
    }

    public void desconectar() {
        jopc.terminate();

//        currentInstance = null;
    }

    @Override
    public void finalize() {
        if (jopc.isRunning()) {
            desconectar();
        }
    }

    public void addVariavel(String nome) {
        if (variaveis.containsKey(nome)) {
            return;
        }
        OpcItem var = new OpcItem(nome, true, "");
        grupoPadrao.addItem(var);
        variaveis.put(nome, var);
    }

    public Object getVariavel(String nome) {
        OpcItem response = null;
        
        //OpcItem item1 = new OpcItem("\\\\.\\nuex\\C12136", true, "");
        //OpcItem item1 = variaveis.get(nome);
        try {
           response = jopc.synchReadItem(grupoPadrao, variaveis.get(nome));
        } catch (SynchReadException e) {
            e.printStackTrace();
        }
        System.out.println(Variant.getVariantName(response.getDataType()) + " 1: " + response.getValue());
        return response.getValue().toString();
    }

    public void setVariavel(String nome, double valor) {
        OpcItem item = variaveis.get(nome);
        item.setValue(new Variant(valor));
        try {
            jopc.synchWriteItem(grupoPadrao, item);
        } catch (SynchWriteException e) {
            e.printStackTrace();
        }
    }

    /*
     * public int compareTo(ConexaoOPC that) { return
     * this.getServerName().compareTo(that.getServerName()); }
     */
    public String getServerName() {
        return serverName;
    }

    public static ConexaoOPC newInstance(String host, String serverName, int handle) {
        currentInstance = new ConexaoOPC(host, serverName, handle);

        return currentInstance;
    }

    public static ConexaoOPC getCurrentInstance() {
        return currentInstance;
    }

    public boolean isInstance(String host, String serverName) {
        return host.equals(currentInstance.getHost()) && serverName.equals(currentInstance.getServerName());
    }

    public boolean isRunning() {
        return jopc.isRunning();
    }

    public static boolean isConnected() {
        return currentInstance != null && currentInstance.conectado;
    }

    public static boolean jbrowserIsConnercted(){
        return currentInstance!= null && currentInstance.jbrowserConectado;
    }
    
    public int getId() {
        return id;
    }

    public void JbrowserConect() throws ConnectivityException {
        jbrowserConectado = true;
        jbrowser.connect();
    }

    public ArrayList<String[]> listarStringItens() throws ConnectivityException {
        ArrayList<String[]> List_Itens_por_grupo = new ArrayList<String[]>();
        try {
            String[] branches = jbrowser.getOpcBranch("");
            for (int i = 0; i < branches.length; i++) {
                List_Itens_por_grupo.add(jbrowser.getOpcItems(branches[i], conectado));
            }

        } catch (UnableBrowseBranchException ex) {
            Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnableIBrowseException ex) {
            Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnableBrowseLeafException ex) {
            Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnableAddGroupException ex) {
            Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnableAddItemException ex) {
            Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return List_Itens_por_grupo;

    }

    public void imprimirItemCompleto() {
        OpcItem itemRead = null;
        for (int i = 0; i < grupoPadrao.getItems().size(); i++) {
            try {
                itemRead = jopc.synchReadItem(grupoPadrao, grupoPadrao.getItems().get(i));
            } catch (ComponentNotFoundException ex) {
                Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SynchReadException ex) {
                Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println(itemRead);
        }
    }

    /**
     * Lista os dispositivos do Servidor. ex: device.
     *
     * @return Lista de string.
     */
    public String[] ListarDispositivos() throws ConnectivityException {
        String[] branches = null;
        try {
            
            jbrowser.connect();
            branches = jbrowser.getOpcBranch("");
          
       
        } catch (UnableBrowseBranchException | UnableIBrowseException ex) {
            Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return branches;

    }
    
    public String[] ListarDispositivosDeDispositivos(String branch) throws ConnectivityException, UnableBrowseBranchException {
        String[] branches = null;
        
            
            jbrowser.connect();

            try {
                branches = jbrowser.getOpcBranch(branch);
            } catch (UnableIBrowseException ex) {
                Logger.getLogger(ConexaoOPC.class.getName()).log(Level.SEVERE, null, ex);
            }
            

            
          
       

        return branches;

    }    

    public String[] getItem(String branche) throws UnableBrowseLeafException, UnableIBrowseException, UnableAddGroupException, UnableAddItemException {
        return jbrowser.getOpcItems(branche, true);
        
        
    }
    
    public String[] test(String branche) throws UnableBrowseLeafException, UnableIBrowseException, UnableAddGroupException, UnableAddItemException {
        return jbrowser.getOpcItems(branche, true);
        
    }
}